package com.group.project.hrms.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.group.project.hrms.entity.*;
import com.group.project.hrms.entity.ResultEntity.ResultEntity;
import com.group.project.hrms.service.*;
import com.group.project.hrms.utils.DESUtil;
import com.group.project.hrms.utils.JwtUtilForHRMS;
import com.group.project.hrms.utils.LogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 该类是所有前端登录时首先访问的类，用于向前端合法用户发放Token
 */
@Controller
public class LoginController {

    private Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private IDingAuthInfoService iDingAuthInfoService;

    @Autowired
    private ISystemAdminInfoService adminInfos;

    @Autowired
    private IContactBasicService iContactBasicService;

    @Autowired
    private ISystemAuthenticationListService iSystemAuthenticationListService;

    @Autowired
    private ISystemAuthorityListService iSystemAuthorityListService;

    @Autowired
    private LogUtil logUtil;


    public static com.aliyun.dingtalkoauth2_1_0.Client authClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

    public static com.aliyun.dingtalkcontact_1_0.Client contactClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkcontact_1_0.Client(config);
    }


    /**
     * 前端登录页面中，如果使用钉钉扫码，就会请求此接口，此接口返回钉钉扫码页面需要的钉钉认证信息
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/login/getDingAppRedirectUri")
    @ResponseBody
    public ResultEntity getDingAppRedirectUri(HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date date = new Date();
        String ip = request.getRemoteAddr();
        logger.info("IP地址为：" + ip + " 在" + date + " 获取了钉钉扫码所需的配置信息!");
        Map<String, String> map = new HashMap<>();
        List<Map> targetList = new ArrayList<>();
        try{
            List<DingAuthInfo> list = iDingAuthInfoService.selectAllDingAuthInfo();
            if(null == list || list.size() == 0){
                resultEntity.setCode("F");
                resultEntity.setMsg("尚未配置钉钉扫码");
                return resultEntity;
            }else{
                DingAuthInfo dingAuthInfo = list.get(0);
                map.put("clientID", dingAuthInfo.getAppKey());
                map.put("url", dingAuthInfo.getRedirectUri());
                targetList.add(map);
                resultEntity.setCode("S");
                resultEntity.setDataList(targetList);
                logUtil.insertSystemEventLog(ip, date, "获取了钉钉扫码所需的配置信息", "系统");
                return resultEntity;
            }
        }catch (Exception e){
            e.printStackTrace();
            resultEntity.setCode("F");
            resultEntity.setMsg("数据库访问异常");
            return resultEntity;
        }
    }


    /**
     * 该方法将接收前端的钉钉扫码事件的响应，并通过登录authCode获取扫码用户的信息，并从认证列表中获取该用户的信息进行比对
     * @param request
     * @param map authCode数据对象
     * @return 本系统后台生成的token
     */
    @RequestMapping("/login/dingRequest")
    @ResponseBody
    public ResultEntity dingRequest(HttpServletRequest request, @RequestBody Map map) {
        String ip = request.getRemoteAddr();
        Date date = new Date();
        logger.info("IP地址为：" + ip + " 在" + date + " 尝试进行了扫码登录本系统!");
        ResultEntity resultEntity = new ResultEntity();
        if(null != map){
            String authCode = map.get("authCode").toString();
            try{
                //System.out.println(getAccessTokenWithUserInfo(authCode));
                JSONObject userObject = JSON.parseObject(getAccessTokenWithUserInfo(authCode));
                ContactBasic basic = iContactBasicService.selectContactBasicByUnID(userObject.getString("unionId"));
                if(null == basic){
                    resultEntity.setCode("F");
                    resultEntity.setMsg("系统中无此用户");
                    return resultEntity;
                }else {
                    String contactID = basic.getContactId();
                    SystemAuthenticationList authenticationList = iSystemAuthenticationListService.selectSystemAuthenticationListByContactId(contactID);
                    if(null == authenticationList){
                        resultEntity.setCode("F");
                        resultEntity.setMsg("您无权登录本系统");
                        return resultEntity;
                    }else {
                        String authFlag = "";
                        String authIDs = authenticationList.getAuthIds();
                        if(null != authIDs){
                            JSONArray jsonArray = JSON.parseArray(authIDs);
                            for (int i = 0; i < jsonArray.size(); i++) {
                                String id = jsonArray.getString(i);
                                SystemAuthorityList authorityList = iSystemAuthorityListService.selectSystemAuthorityListByAuthorityId(id);
                                authFlag = authFlag + authorityList.getAuthorityFlag();
                            }
                        }

                        //验证通过后，返回前端需要的信息
                        Map<String, Object> resultMap = new HashMap<>();
                        resultMap.put("contactID", basic.getContactId());
                        resultMap.put("userName", basic.getStaffName());
                        resultMap.put("authenticationList", authFlag);
                        resultMap.put("token", JwtUtilForHRMS.createToken(basic));
                        List<Map> resultList = new ArrayList<>();
                        resultList.add(resultMap);
                        resultEntity.setCode("S");
                        resultEntity.setMsg("Success");
                        resultEntity.setDataList(resultList);
                        logUtil.insertSystemEventLog(basic.getStaffName() + "(" + ip + ")", date, "通过扫码登录了本系统", "系统");
                        return resultEntity;
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                resultEntity.setCode("F");
                resultEntity.setMsg("无法获取您的访问权限");
                return resultEntity;
            }
        }else {
            resultEntity.setCode("F");
            resultEntity.setMsg("无法获取扫码识别码信息");
            return resultEntity;
        }
    }

    /**
     * 获取访问钉钉使用的Token后，再获取个人信息
     * @param authCode
     * @return
     * @throws Exception
     */
    private String getAccessTokenWithUserInfo(String authCode) throws Exception {
        DingAuthInfo dingAuthInfo = iDingAuthInfoService.selectAllDingAuthInfo().get(0);
        com.aliyun.dingtalkoauth2_1_0.Client client = authClient();
        GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
                //应用基础信息-应用信息的AppKey
                .setClientId(dingAuthInfo.getAppKey())
                //应用基础信息-应用信息的AppSecret
                .setClientSecret(dingAuthInfo.getAppSecret())
                .setCode(authCode)
                .setGrantType("authorization_code");
        GetUserTokenResponse getUserTokenResponse = client.getUserToken(getUserTokenRequest);
        //获取用户个人token
        String accessToken = getUserTokenResponse.getBody().getAccessToken();
        return  getUserInfo(accessToken);

    }


    /**
     * 获取用户个人信息
     * @param accessToken
     * @return
     * @throws Exception
     */
    private String getUserInfo(String accessToken) throws Exception {
        com.aliyun.dingtalkcontact_1_0.Client client = contactClient();
        GetUserHeaders getUserHeaders = new GetUserHeaders();
        getUserHeaders.xAcsDingtalkAccessToken = accessToken;
        //获取用户个人信息，如需获取当前授权人的信息，unionId参数必须传me
        String me = JSON.toJSONString(client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions()).getBody());
        //System.out.println(me);
        return me;
    }


    /**
     * 该接口主要针对非扫码登录的认证，即用户名和密码形式的登录，包含系统内置管理员登录
     * @return  返回token , A表示用户名或密码为空, B表示无此用户, C表示密码错误, D表示用户名或者密码错误
     */
    @RequestMapping("/login/non_scanning_code")
    @ResponseBody
    public ResultEntity nonScanningLogin(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Map<String, Object> resultMap = new HashMap<>();
        List<Map> resultList = new ArrayList<>();

        String ip = request.getRemoteAddr();

        Object uname = map.get("username");
        Object pwd = map.get("password");

        //从数据库中获取用户信息
        if(null == uname || null == pwd){
            resultEntity.setCode("F");
            resultEntity.setMsg("用户名或密码为空");
            return resultEntity;//username or password is empty
        }else {

            String username;
            String password;

            //System.out.println("前端传入的加密用户名和密码分别为: " + uname + " / " + pwd);

            try{
                username = DESUtil.decryption(uname.toString(), DESUtil.DES_KEY);
                password = DESUtil.decryption(pwd.toString(), DESUtil.DES_KEY);

                //System.out.println("解密后的用户名和密码：" + username + " / " + password);

            }catch (Exception e){
                e.printStackTrace();
                resultEntity.setCode("F");
                resultEntity.setMsg("校验登录密钥时错误");
                return resultEntity;
            }

            List<SystemAdminInfo> adminList = adminInfos.selectAllSystemAdminInfo();
            Iterator<SystemAdminInfo> infoIterator = adminList.iterator();
            while (infoIterator.hasNext()){
                SystemAdminInfo systemAdminInfo = infoIterator.next();
                if(systemAdminInfo.getUserName().equals(username)){
                    if(systemAdminInfo.getPwd().equals(password)){
                        ContactBasic basic = new ContactBasic();
                        basic.setStaffName(systemAdminInfo.getUserName());
                        basic.setDingUserid(systemAdminInfo.getUserId());
                        basic.setContactId(systemAdminInfo.getUserId());
                        String token = JwtUtilForHRMS.createToken(basic);
                        logger.info("User " + username +" has got the token :" + token);
                        resultEntity.setCode("S");
                        resultEntity.setMsg("Success");
                        resultMap.put("jwToken", token);
                        resultMap.put("authenticationList", "FIBDG");//BDG
                        resultMap.put("userName", username);
                        resultList.add(resultMap);
                        resultEntity.setDataList(resultList);
                        logUtil.insertSystemEventLog(username + "(" + ip + ")", new Date(), "通过用户名和密码的形式登录了本系统", "系统");
                        return resultEntity;
                    }else{
                        logger.info("User " + username +" did input a wrong password!");
                        resultEntity.setCode("F");
                        resultEntity.setMsg("密码输入错误");
                        return resultEntity;
                    }
                }else{
                    logger.info("There is no user named :" + username);
                    resultEntity.setCode("F");
                    resultEntity.setMsg("系统中无此用户");
                    return resultEntity;//there is no this user
                }
            }
            logger.info("username or password is wrong");
            resultEntity.setCode("F");
            resultEntity.setMsg("用户名或密码错误");
            return resultEntity;
        }
    }
}
